﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using System.Diagnostics;
using System.Reflection;
using Hallenberg.SmartClient.Menu;
using Hallenberg.SmartClient.Interfaces;
using System.Collections.ObjectModel;

namespace Hallenberg.SmartClient.MVC
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
    public class ControllerFactoryEx : DefaultControllerFactory
    {
        public const string CurrentMenuManager = "CurrentMenuManager";
        public const string SelectedMenuItems = "SelectedMenuItems";
        public const string DependentMenuItems = "DependentMenuItems";

        public IController GetControllerInstanceTest(Type controllerType)
        {
            return GetControllerInstance(controllerType);
        }

        protected override IController GetControllerInstance(Type controllerType)
        {
            if (controllerType == null)
            {
                return null;
            }

            ///////////////////////////////////////////////////////////////////
            // Build up controller using Unity.
            ///////////////////////////////////////////////////////////////////

            Controller controller = MvcSmartClientApplication.GlobalWorkItem.Services.Resolve(controllerType) as Controller;

            Debug.Assert(controller != null);
            if (controller == null)
            {
                throw new InvalidOperationException("Resolved type is not an MCV controller");
            }

            ///////////////////////////////////////////////////////////////////
            // Get the controller method pointed to by the RouteData's action
            // name. Then examine if the method has a menu item attribute
            // assigned. From this value calculate the current menu and
            // what menus are currently 'selected'.
            ///////////////////////////////////////////////////////////////////

            string actionName = this.RequestContext.RouteData.Values["action"] as string;

            Debug.Assert(string.IsNullOrEmpty(actionName) == false);
            if (string.IsNullOrEmpty(actionName))
            {
                throw new InvalidOperationException("RouteData for current request does not contain an 'action' value");
            }

            MemberInfo member = controllerType.GetMember(actionName).FirstOrDefault();
            MenuItemAttribute menuItemAttribute = member.GetCustomAttributes(typeof(MenuItemAttribute), true).FirstOrDefault() as MenuItemAttribute;

            if (menuItemAttribute != null)
            {
                MenuItemContainer currentManager = MvcSmartClientApplication.GlobalWorkItem.MenuManagers.Find(menuItemAttribute.MenuCollectionName, false);

                Debug.Assert(currentManager != null);
                if (currentManager == null)
                {
                    throw new InvalidOperationException(
                        "MenuItemAttribute on controller '" + controllerType.Name + "' / '" +
                        actionName + "' contains an invalid MenuCollectionName");
                }

                controller.ViewData.Add(ControllerFactoryEx.CurrentMenuManager, currentManager);

                ReadOnlyCollection<MenuItem> selectedMenuItems = MvcSmartClientApplication.GlobalWorkItem.MenuManagers.GetSelectedMenuItems(menuItemAttribute.MenuCollectionName, menuItemAttribute.MenuItemName);

                controller.ViewData.Add(
                    ControllerFactoryEx.SelectedMenuItems,
                    selectedMenuItems);

                ///////////////////////////////////////////////////////////////////
                // Set primary dependent menu item collection.
                ///////////////////////////////////////////////////////////////////

                MenuItemContainer menuManager = MvcSmartClientApplication.GlobalWorkItem.MenuManagers.Find(menuItemAttribute.MenuItemName, false);
                if (menuManager != null)
                {
                    controller.ViewData.Add(ControllerFactoryEx.DependentMenuItems, new ReadOnlyCollection<MenuItem>(menuManager.ChildItems.ToList()));
                }
                else
                {
                    controller.ViewData.Add(ControllerFactoryEx.DependentMenuItems, new ReadOnlyCollection<MenuItem>(new List<MenuItem>()));
                }
            }

            ///////////////////////////////////////////////////////////////////
            // Set the language based on the session variable.
            ///////////////////////////////////////////////////////////////////

            MvcSmartClientApplication.GlobalWorkItem.Services.Resolve<ILocalization>().SetStoredLanguage();

            return (IController)controller;
        }
    }
}
